﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using dw = System.Drawing;

namespace client.app.world
{
    public class SObject : comm.world.BSObject, IBObject
    {
        public float DisplayX { get; private set; }
        public float DisplayY { get; private set; }
        public string DObjectId { get; private set; }
        public string PlayerId { get; private set; }

        Space _space = null;
        Texture2D _texObjDot1 = null,
            _texObjDot2 = null,
            _texSelectBorder = null,
            _texMovePathDot = null,
            _texMy = null,
            _texArcDot = null;
        SpriteBatch _spriteBatch = null;
        float _moveXStep = 0, _moveYStep = 0;

        LightSource _lightSource = new LightSource();
        bool _created = false;

        int[][] _arcDots = null;

        comm.objst.DObject _dobj = null;
        ObjAction _objAction = null;
        RSprite _rSprite = null;

        public SObject(Space space, comm.world.BSpace.LocManager locManager, comm.objst.SObjectInfo sobjInfo)
            : base(space, locManager, sobjInfo.ObjectId)
        {
            _space = space;
            DObjectId = sobjInfo.DObjectId;
            PlayerId = sobjInfo.PlayerId;

            MoveType = sobjInfo.MoveType;
            MoveSpeed = sobjInfo.MoveSpeed;

            ObservedRadius = 10;
            StartObserved();

            _dobj = MainGame.DefineFile.GetObject(DObjectId);
            var dobjData = MainGame.DefineFile.GetObjectData(DObjectId);

            _objAction = new ObjAction(this, dobjData.ActionDic, comm.objst.ObjActionType.IDLE.ToString());

            _rSprite = new RSprite(_space.LayerManager);
            _rSprite.LoadRSprite(_dobj.RPackFile, DObjectId + "_" + comm.objst.ObjActionType.IDLE);
            _space.LayerManager.AddRSprite(_rSprite);

            MainGame.Instance.AddTask(() =>
            {
                _spriteBatch = new SpriteBatch(MainGame.Instance.GraphicsDevice);

                _space.LightMask.AddLightSource(_lightSource);

                #region _texObjDot2 init
                using (var bitmap = new dw.Bitmap(10, 10))
                {
                    bitmap.Draw(g =>
                    {
                        g.FillEllipse(dw.Color.Black.SolidBrush(60), 0, 0, 10, 10);
                    });
                    bitmap.Save(ms =>
                    {
                        _texObjDot1 = Texture2D.FromStream(MainGame.Instance.GraphicsDevice, ms);
                    });

                    bitmap.Draw(g =>
                    {
                        g.Clear(dw.Color.Transparent);
                        g.FillEllipse(dw.Color.Blue.SolidBrush(60), 0, 0, 10, 10);
                    });
                    bitmap.Save(ms =>
                    {
                        _texObjDot2 = Texture2D.FromStream(MainGame.Instance.GraphicsDevice, ms);
                    });

                    bitmap.Draw(g =>
                    {
                        g.Clear(dw.Color.Transparent);
                        g.DrawRectangle(dw.Color.White.Pen(), 0, 0, 10, 10);
                    });
                    bitmap.Save(ms =>
                    {
                        _texArcDot = Texture2D.FromStream(MainGame.Instance.GraphicsDevice, ms);
                    });
                }
                #endregion

                #region _texSelectBorder init
                using (var bitmap = new dw.Bitmap(10, 10))
                {
                    bitmap.Draw(g =>
                    {
                        g.DrawEllipse(dw.Color.Green.Pen(30), 0, 0, 10, 10);
                    }, dw.Drawing2D.SmoothingMode.HighSpeed);
                    bitmap.Save(ms =>
                    {
                        _texSelectBorder = Texture2D.FromStream(MainGame.Instance.GraphicsDevice, ms);
                    });
                }
                #endregion

                #region _texMovePathDot init
                using (var bitmap = new dw.Bitmap(10, 10))
                {
                    bitmap.Draw(g =>
                    {
                        g.FillEllipse(dw.Color.Black.SolidBrush(20), 0, 0, 10, 10);
                    });
                    bitmap.Save(ms =>
                    {
                        _texMovePathDot = Texture2D.FromStream(MainGame.Instance.GraphicsDevice, ms);
                    });
                }
                #endregion

                #region _texMy init
                using (var bitmap = new dw.Bitmap(4, 4))
                {
                    bitmap.Draw(g =>
                    {
                        g.Clear(dw.Color.GreenYellow);
                    });
                    bitmap.Save(ms =>
                    {
                        _texMy = Texture2D.FromStream(MainGame.Instance.GraphicsDevice, ms);
                    });
                }
                #endregion

                _created = true;
            });
        }

        public void BeginDraw(comm.TimeStat timeStat)
        {
        }
        public void Draw(comm.TimeStat timeStat)
        {
            if (!_created)
            {
                return;
            }
            _spriteBatch.Begin();

            if (MoveType != comm.objst.MoveType.FLIGHT && MovingSteps != null)
            {
                foreach (var dot in MovingSteps)
                {
                    _spriteBatch.Draw(_texMovePathDot, new Rectangle(
                        (int)(dot[0] * PathSize * _space.MapPathSize + _space.OffsetX),
                        (int)(dot[1] * PathSize * _space.MapPathSize + _space.OffsetY),
                        PathSize * _space.MapPathSize,
                        PathSize * _space.MapPathSize), Color.White);
                }
            }

            _spriteBatch.Draw(MoveType == comm.objst.MoveType.FLIGHT ? _texObjDot2 : _texObjDot1, new Rectangle(
                 (int)(DisplayX + _space.OffsetX),
                 (int)(DisplayY + _space.OffsetY),
                 PathSize * _space.MapPathSize,
                 PathSize * _space.MapPathSize), Color.White);

            if (_space.SObjectIsSelect(ObjectId))
            {
                _spriteBatch.Draw(_texSelectBorder, new Rectangle(
                    (int)(DisplayX - 2 + _space.OffsetX),
                    (int)(DisplayY - 2 + _space.OffsetY),
                    PathSize * _space.MapPathSize + 4,
                    PathSize * _space.MapPathSize + 4), Color.White);
            }

            if (MainGame.MainSpace.PlayerId == PlayerId)
            {
                _spriteBatch.Draw(_texMy, new Vector2(
                    (int)(DisplayX - 2 + _space.OffsetX),
                    (int)(DisplayY - 2 + _space.OffsetY)), Color.White);
            }

            if (_arcDots != null)
            {
                foreach (var dot in _arcDots)
                {
                    _spriteBatch.Draw(_texArcDot, new Vector2(
                        (int)(dot[0] * BSpace.MapPathSize - 2 + _space.OffsetX),
                        (int)(dot[1] * BSpace.MapPathSize - 2 + _space.OffsetY)), Color.White);
                }
            }

            _spriteBatch.End();
        }

        void BeginMove(int fromX, int fromY, int toX, int toY, double maxMS)
        {
            _moveXStep = (toX * PathSize * BSpace.MapPathSize - DisplayX) / (float)maxMS;
            _moveYStep = (toY * PathSize * BSpace.MapPathSize - DisplayY) / (float)maxMS;

            if (MainGame.MainSpace.PlayerId == PlayerId)
            {
                var moveTo = new comm.objst.MoveTo
                {
                    ObjectId = ObjectId,
                    FromX = fromX,
                    FromY = fromY,
                    ToX = toX,
                    ToY = toY
                };
                TcpClient.Call(comm.objst.TcpMessageType.ToServerSpaceObjectBeginMove, new comm.objst.MoveTo[] { moveTo }, message =>
                {
                    message.TryToObject<comm.objst.MoveToResult[]>(results =>
                    {
                        var result = results[0];
                        if (MoveType != comm.objst.MoveType.FLIGHT && (!result.CheckLoc || !result.CanEnter))
                        {
                            var ms = (long)comm.MathHelper.PointDistance(LocX, LocY, result.LocX, result.LocY) * MoveSpeed;
                            BeginMove(result.LocX, result.LocY, ms);
                            Console.WriteLine("MoveToResult CheckLoc:" + result.CheckLoc + " CanEnter:" + result.CanEnter, comm.ConsoleColor.RED);
                        }
                    });
                });
            }
        }

        protected override void OnBeginStepMove(int fromX, int fromY, int toX, int toY, double maxMS)
        {
            if (MoveType != comm.objst.MoveType.FLIGHT)
            {
                BeginMove(fromX, fromY, toX, toY, maxMS);
            }
            var groupName = comm.MathHelper.PointDir(fromX, fromY, toX, toY).ToString();
            if (_rSprite.SpriteGroupName != groupName)
            {
                _rSprite.ChangeGroup(groupName);
            }
            base.OnBeginStepMove(fromX, fromY, toX, toY, maxMS);
        }
        protected override void OnBeginMove(int fromX, int fromY, int toX, int toY, double maxMS)
        {
            if (MoveType == comm.objst.MoveType.FLIGHT)
            {
                BeginMove(fromX, fromY, toX, toY, maxMS);
            }
            _rSprite.LoadRSprite(_dobj.RPackFile, DObjectId + "_" + comm.objst.ObjActionType.MOVE);
            _rSprite.ChangeGroup(comm.MathHelper.PointDir(fromX, fromY, toX, toY).ToString());
            base.OnBeginMove(fromX, fromY, toX, toY, maxMS);
        }
        protected override void OnEndMove()
        {
            _objAction.Exec(comm.objst.ObjActionType.IDLE.ToString());
            var groupName = _rSprite.SpriteGroupName;
            _rSprite.LoadRSprite(_dobj.RPackFile, DObjectId + "_" + comm.objst.ObjActionType.IDLE);
            _rSprite.ChangeGroup(groupName);
            base.OnEndMove();
        }
        protected override void OnUpdateMove(double ms)
        {
            DisplayX += _moveXStep * (float)ms;
            DisplayY += _moveYStep * (float)ms;

            base.OnUpdateMove(ms);
        }
        protected override void OnSetLoc(int oldX, int oldY, int newX, int newY)
        {
            if (!Moveing)
            {
                DisplayX = LocX * PathSize * BSpace.MapPathSize;
                DisplayY = LocY * PathSize * BSpace.MapPathSize;
            }

            base.OnSetLoc(oldX, oldY, newX, newY);
        }
        protected override void OnUpdate(comm.TimeStat timeStat)
        {
            _objAction.Update(timeStat);

            _rSprite.DisplayX = DisplayX + _space.OffsetX + PathSize * _space.MapPathSize / 2;
            _rSprite.DisplayY = DisplayY + _space.OffsetY + PathSize * _space.MapPathSize / 2;

            _lightSource.Radius = PathSize + 20;
            _lightSource.X = LocX * PathSize + PathSize / 2;
            _lightSource.Y = LocY * PathSize + PathSize / 2;

            base.OnUpdate(timeStat);
        }
    }
}